package it.poste.il.compensatore.dao.impl;

import java.util.List;


import org.springframework.dao.DataAccessException;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import it.poste.il.compensatore.dao.BaseEntityDao;
import it.poste.il.compensatore.entities.BaseEntity;
import it.poste.il.compensatore.exceptions.dao.EntityNotFoundException;

/**
 * Implementation of BaseEntityDao.
 */
@SuppressWarnings("deprecation")
public abstract class BaseEntityDaoImpl<T extends BaseEntity> extends JpaDaoSupport implements BaseEntityDao<T> {

    @PersistenceContext
    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }
    
    private Class<T> prototype;
    private String entityName;

    public BaseEntityDaoImpl(Class<T> prototype, String entityName) {
        this.prototype = prototype;
        this.entityName = entityName;
    }

    protected final T newPrototype(Class<T> cl) throws IllegalArgumentException {
        try {
            return cl.newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }

	/**
	 * Take entity from id.
	 * @param entityId Id of the entity.
	 * @return T Entity that return.
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public T loadById(Long entityId) throws EntityNotFoundException {
        T entity = entityManager.find(prototype, entityId);
        if (entity == null) {
            throw new EntityNotFoundException(prototype, entityId);
        }
        return entity;
    }

	/**
	 * Take list of the entity.
	 * @return List<T> List of the entity.
	 */
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public List<T> loadAll() throws DataAccessException {
        Query query = getEntityManager().createQuery("select obj from " + entityName + " obj order by obj.id");
        //noinspection unchecked
		List<T> resultList = query.getResultList();
        return resultList;
    }

	/**
	 * Save of the entity.
	 * @param T Entity to save.
	 * @return T Entity that return.
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public T save(T entity) {
        if (entity.getId() != null) {
            entityManager.merge(entity);
        } else {
            entityManager.persist(entity);
        }
        return entity;
    }

	/**
	 * Update of the entity.
	 * @param T Entity to update.
	 * @return void
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void update(T entity) {
        T loadedEntity = loadById(entity.getId());
		entityManager.merge(loadedEntity);
	}

	/**
	 * Delete of the entity.
	 * @param T Entity to delete.
	 * @return void
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public void delete(T entity) {
        T loadedEntity = loadById(entity.getId());
        entityManager.remove(loadedEntity);
	}

}
